/*
 * Created on 2004-10-13
 */
package org.opencube.oms;

import java.util.HashMap;
import java.util.LinkedList;

import org.opencube.data.BoundVariable;
import org.opencube.data.DataSource;
import org.opencube.data.Record;
import org.opencube.oms.meta.OMSMetaData;

/**
 * @author <a href="mailto:maciek@fingo.pl">Maciej Mroczko - FINGO</a>
 *
 * TODO comments
 */
class BatchHelper extends DBHelper
{
	// ids sequence names 
	static final String SEQ_ELEMENT_ID = "ELEMENT_ELM_ID_SEQ";
	static final String SEQ_SIMPLE_VALUE_ID = "SIMPLEVALUE_SVL_ID_SEQ";
	static final String SEQ_CLOB_VALUE_ID = "CLOBVALUE_CVL_ID_SEQ";
	static final String SEQ_BLOB_VALUE_ID = "BLOBVALUE_BVL_ID_SEQ";
	static final String SEQ_UNIQUE_VALUE_ID = "UNIQUEVALUE_UVL_ID_SEQ";
	static final String SEQ_COMPOSITION_ID = "COMPOSITION_CMP_ID_SEQ";
	static final String SEQ_ASSOCIATION_ID = "ASSOCIATION_ASS_ID_SEQ";
	
	/* Resources for batching */
	
	// inserts
	static final String BATCH_RESOURCE_CREATE_ELEMENTS = "element.createElement_no_out";
	static final String BATCH_RESOURCE_CREATE_SIMPLE_VALUES = "element.createSimpleValue_no_out";
	static final String BATCH_RESOURCE_CREATE_CLOB_VALUES = "element.createClobValue_no_out";
	static final String BATCH_RESOURCE_CREATE_BLOB_VALUES = "element.createBlobValue_no_out";
	static final String BATCH_RESOURCE_CREATE_UNIQUE_VALUES = "element.createUniqueValue_no_out";
	static final String BATCH_RESOURCE_APPEND_COMPOSITIONS = "relation.appendComposition_no_out";
	static final String BATCH_RESOURCE_APPEND_ASSOCIATIONS = "relation.appendAssociation_no_out";
	// deletes
	static final String BATCH_RESOURCE_REMOVE_ELEMENTS = "element.removeElement_no_out";
	static final String BATCH_RESOURCE_REMOVE_SIMPLE_VALUES = "element.removeSimpleValue_no_out";
	static final String BATCH_RESOURCE_REMOVE_CLOB_VALUES = "element.removeClobValue_no_out";
	static final String BATCH_RESOURCE_REMOVE_BLOB_VALUES = "element.removeBlobValue_no_out";
	static final String BATCH_RESOURCE_REMOVE_UNIQUE_VALUES = "element.removeUniqueValue_no_out";
	static final String BATCH_RESOURCE_REMOVE_ASSOCIATIONS = "relation.removeAssociation_no_out";
	static final String BATCH_RESOURCE_REMOVE_COMPOSITIONS = "relation.removeComposition_no_out";
	// updates
	static final String BATCH_RESOURCE_UPDATE_ELEMENTS = "element.updateElement_no_out";
	static final String BATCH_RESOURCE_UPDATE_SIMPLE_VALUES = "element.updateSimpleValue_no_out";
	static final String BATCH_RESOURCE_UPDATE_CLOB_VALUES = "element.updateClobValue_no_out";
	static final String BATCH_RESOURCE_UPDATE_BLOB_VALUES = "element.updateBlobValue_no_out";
	static final String BATCH_RESOURCE_UPDATE_UNIQUE_VALUES = "element.updateUniqueValue_no_out";
	// sequence values
	static final String RESOURCE_GET_SEQUENCE_VALUES_FROM_ELEMENTS = "getSequenceValuesFromElements";
	static final String RESOURCE_GET_SEQUENCE_VALUES_FROM_DUAL = "getSequenceValuesFromDual";

	int executeBatch( DataSource dataSource, String resource, BoundVariable[][] vars )
	throws Exception
	{
		String statement = ResourceHelper.loadResource( resource, dataSource.getType() );
		return dataSource.executeBatch( statement, vars, ResourceHelper.getNamespace( resource, dataSource.getType() ), ResourceHelper.getResourceFileName( resource ) );
	}	

	int createElements( OMSMetaData metaData, DataSource dataSource, OMSElement[] elements, int userId )
	throws Exception
	{
		if( !( elements.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.createElements( metaData, dataSource, elements, userId );
		}
		int[] ids = getSequenceValues( dataSource, SEQ_ELEMENT_ID, elements.length );
		BoundVariable[][] vars = new BoundVariable[ elements.length ][];
		for( int i = 0; i < elements.length; i++ )
		{
			if( elements[ i ].getDisplayName() == null )
			{
				elements[ i ].setDisplayName( elements[ i ].getBookmark() );
			}
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( ids[ i ] ) ),
				new BoundVariable( "in_string_display_name", elements[ i ].getDisplayName() ),
				new BoundVariable( "in_string_bookmark", elements[ i ].getBookmark() ),
				new BoundVariable( "in_int_schema_id", metaData.getScheme( elements[ i ].getNamespacePath(), elements[ i ].getSchemeName() ).getId() ),
				new BoundVariable( "in_int_creater_id", new Integer( userId ) ),
			};
			elements[ i ].setId( ids[ i ] + "" );
		}
	
		int result = executeBatch( dataSource, BATCH_RESOURCE_CREATE_ELEMENTS, vars );
		resetState( elements );
		return result;
	}
	
	int createSimpleValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.createSimpleValues( metaData, dataSource, values, userId );
		}
		int[] ids = getSequenceValues( dataSource, SEQ_SIMPLE_VALUE_ID, values.length );
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for( int i = 0; i < values.length; i++ )
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( ids[ i ] ) ),
				new BoundVariable( "in_string_content", values[ i ].getContentAsString() ),
				new BoundVariable( "in_int_elm_id", new Integer( values[ i ].getElement().getId() ) ),
				new BoundVariable( "in_int_sat_id", new Integer( metaData.getSimpleAttributeFromHierarchy( metaData.getScheme( values[ i ].getElement().getNamespacePath(), values[ i ].getElement().getSchemeName() ), values[ i ].getSimpleAttribute() ).getId() ) ),
				new BoundVariable( "in_int_dov_id", new Integer( metaData.getSimpleAttributeFromHierarchy( metaData.getScheme( values[ i ].getElement().getNamespacePath(), values[ i ].getElement().getSchemeName() ), values[ i ].getSimpleAttribute() ).getDatatype().getDatatypeEnumerationByName( values[ i ].getDatatypeEnumeration() ).getId() ) ),
				new BoundVariable( "in_int_creater_id", new Integer( userId ) ),
			};
			values[ i ].setId( ids[ i ] + "" );
		}
	
		int result = executeBatch( dataSource, BATCH_RESOURCE_CREATE_SIMPLE_VALUES, vars );
		resetState( values );
		return result;
	}

	int createClobValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.createClobValues( metaData, dataSource, values, userId );
		}
		int[] ids = getSequenceValues( dataSource, SEQ_CLOB_VALUE_ID, values.length );
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for( int i = 0; i < values.length; i++ )
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( ids[ i ] ) ),
				new BoundVariable( "in_clob_content", values[ i ].getContentAsString() ),
				new BoundVariable( "in_int_elm_id", new Integer( values[ i ].getElement().getId() ) ),
				new BoundVariable( "in_int_sat_id", new Integer( metaData.getSimpleAttributeFromHierarchy( metaData.getScheme( values[ i ].getElement().getNamespacePath(), values[ i ].getElement().getSchemeName() ), values[ i ].getSimpleAttribute() ).getId() ) ),
				new BoundVariable( "in_int_dov_id", new Integer( metaData.getSimpleAttributeFromHierarchy( metaData.getScheme( values[ i ].getElement().getNamespacePath(), values[ i ].getElement().getSchemeName() ), values[ i ].getSimpleAttribute() ).getDatatype().getDatatypeEnumerationByName( values[ i ].getDatatypeEnumeration() ).getId() ) ),
				new BoundVariable( "in_int_creater_id", new Integer( userId ) ),
			};
			values[ i ].setId( ids[ i ] + "" );
		}
	
		int result = executeBatch( dataSource, BATCH_RESOURCE_CREATE_CLOB_VALUES, vars );
		resetState( values );
		return result;
	}

	int createBlobValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.createBlobValues( metaData, dataSource, values, userId );
		}
		int[] ids = getSequenceValues( dataSource, SEQ_BLOB_VALUE_ID, values.length );
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for( int i = 0; i < values.length; i++ )
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( ids[ i ] ) ),
				new BoundVariable( "in_string_content", values[ i ].getContentAsByteArray() ),
				new BoundVariable( "in_int_elm_id", new Integer( values[ i ].getElement().getId() ) ),
				new BoundVariable( "in_int_sat_id", new Integer( metaData.getSimpleAttributeFromHierarchy( metaData.getScheme( values[ i ].getElement().getNamespacePath(), values[ i ].getElement().getSchemeName() ), values[ i ].getSimpleAttribute() ).getId() ) ),
				new BoundVariable( "in_int_dov_id", new Integer( metaData.getSimpleAttributeFromHierarchy( metaData.getScheme( values[ i ].getElement().getNamespacePath(), values[ i ].getElement().getSchemeName() ), values[ i ].getSimpleAttribute() ).getDatatype().getDatatypeEnumerationByName( values[ i ].getDatatypeEnumeration() ).getId() ) ),
				new BoundVariable( "in_int_creater_id", new Integer( userId ) ),
			};
			values[ i ].setId( ids[ i ] + "" );
		}
	
		int result = executeBatch( dataSource, BATCH_RESOURCE_CREATE_BLOB_VALUES, vars );
		resetState( values );
		return result;
	}

	int createUniqueValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.createUniqueValues( metaData, dataSource, values, userId );
		}
		int[] ids = getSequenceValues( dataSource, SEQ_UNIQUE_VALUE_ID, values.length );
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for( int i = 0; i < values.length; i++ )
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( ids[ i ] ) ),
				new BoundVariable( "in_string_content", values[ i ].getContentAsString() ),
				new BoundVariable( "in_int_elm_id", new Integer( values[ i ].getElement().getId() ) ),
				new BoundVariable( "in_int_sat_id", new Integer( metaData.getSimpleAttributeFromHierarchy( metaData.getScheme( values[ i ].getElement().getNamespacePath(), values[ i ].getElement().getSchemeName() ), values[ i ].getSimpleAttribute() ).getId() ) ),
				new BoundVariable( "in_int_dov_id", new Integer( metaData.getSimpleAttributeFromHierarchy( metaData.getScheme( values[ i ].getElement().getNamespacePath(), values[ i ].getElement().getSchemeName() ), values[ i ].getSimpleAttribute() ).getDatatype().getDatatypeEnumerationByName( values[ i ].getDatatypeEnumeration() ).getId() ) ),
				new BoundVariable( "in_int_creater_id", new Integer( userId ) ),
			};
			values[ i ].setId( ids[ i ] + "" );
		}
	
		int result = executeBatch( dataSource, BATCH_RESOURCE_CREATE_UNIQUE_VALUES, vars );
		resetState( values );
		return result;
	}
	
	int createCompositions( OMSMetaData metaData, DataSource dataSource, Relation[] compositions, int userId )
	throws Exception
	{
		if( !( compositions.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.createCompositions( metaData, dataSource, compositions, userId );
		}
		for (int i = 0; i < compositions.length; i++)
		{
			if( compositions[ i ].isOrdered() && compositions[ i ].getNextRelation() != null  )
			{
				return super.createCompositions( metaData, dataSource, compositions, userId );
			}

		}
		int[] ids = getSequenceValues( dataSource, SEQ_COMPOSITION_ID, compositions.length );
		BoundVariable[][] vars = new BoundVariable[ compositions.length ][];
		for( int i = 0; i < compositions.length; i++ )
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( ids[ i ] ) ),
				new BoundVariable( "in_int_source_id", compositions[ i ].getSourceElementId() ),
				new BoundVariable( "in_int_cat_id", metaData.getComplexAttributeFromHierarchy(  metaData.getScheme( compositions[ i ].getSourceElement().getNamespacePath(), compositions[ i ].getSourceElement().getSchemeName() ), compositions[ i ].getComplexAttribute() ).getId() ),
				new BoundVariable( "in_int_target_id", compositions[ i ].getTargetElement().getId() ),
				new BoundVariable( "in_string_key", compositions[ i ].getName() ),
				new BoundVariable( "in_int_creater_id", new Integer( userId ) ),
			};
			compositions[ i ].setId( ids[ i ] + "" );
		}
	
		int result =  executeBatch( dataSource, BATCH_RESOURCE_APPEND_COMPOSITIONS, vars );
		resetState( compositions );
		return result;
	}

	int createAssociations( OMSMetaData metaData, DataSource dataSource, Relation[] associations, int userId )
	throws Exception
	{
		if( !( associations.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.createAssociations( metaData, dataSource, associations, userId );
		}
		for (int i = 0; i < associations.length; i++)
		{
			if( associations[ i ].isOrdered() && associations[ i ].getNextRelation() != null )
			{
				return super.createAssociations( metaData, dataSource, associations, userId );
			}
		}
		int[] ids = getSequenceValues( dataSource, SEQ_ASSOCIATION_ID, associations.length );
		LinkedList vars = new LinkedList();
		//BoundVariable[][] vars = new BoundVariable[ associations.length ][];
		for( int i = 0; i < associations.length; i++ )
		{
			if( associations[ i ].getState() == OMSNode.STATE_NORMAL )
			{
				continue;
			}
			if( associations[ i ].getTargetElement().isNew() && associations[ i ].getSourceElement().getOMSStructure() != associations[ i ].getTargetElement().getOMSStructure() )
			{
				throw new OMSStructureException( "Exception while saving association: " + getAssociationDescription( associations[ i ], metaData ) + " : Not saved association target element from external oms structure" );
			}
			try
			{
				Integer.parseInt( associations[ i ].getSourceElement().getId() );
			}
			catch( Exception e )
			{
				throw new Exception( "SOURCE INVALID: " + getAssociationDescription( associations[ i ], metaData ), e );
			}
			try
			{
				Integer.parseInt( associations[ i ].getTargetElement().getId() );
			}
			catch( Exception e )
			{
				throw new Exception( "TARGET INVALID: " + getAssociationDescription( associations[ i ], metaData ), e );
			}
			try
			{
				Integer.parseInt( metaData.getComplexAttributeFromHierarchy(  metaData.getScheme( associations[ i ].getSourceElement().getNamespacePath(), associations[ i ].getSourceElement().getSchemeName() ), associations[ i ].getComplexAttribute() ).getId() );
			}
			catch( Exception e )
			{
				throw new Exception( "ATTRIBUTE INVALID: " + getAssociationDescription( associations[ i ], metaData ), e );
			}
			vars.add( new BoundVariable[]
				{
					new BoundVariable( "in_int_id", new Integer( ids[ i ] ) ),
					new BoundVariable( "in_int_source_id", associations[ i ].getSourceElementId() ),
					new BoundVariable( "in_int_cat_id", metaData.getComplexAttributeFromHierarchy(  metaData.getScheme( associations[ i ].getSourceElement().getNamespacePath(), associations[ i ].getSourceElement().getSchemeName() ), associations[ i ].getComplexAttribute() ).getId() ),
					new BoundVariable( "in_int_target_id", associations[ i ].getTargetElement().getId() ),
					new BoundVariable( "in_string_key", associations[ i ].getName() ),
					new BoundVariable( "in_int_creater_id", new Integer( userId ) ),
				}
			);
			
			associations[ i ].setId( ids[ i ] + "" );
			associations[ i ].setState( OMSNode.STATE_NORMAL );
		}
	
		BoundVariable[][] varsArray = (BoundVariable[][]) vars.toArray(new BoundVariable[ vars.size() ][ 6 ] );
		int result = executeBatch( dataSource, BATCH_RESOURCE_APPEND_ASSOCIATIONS, varsArray );
		resetState( associations );
		return result;
	}
	
	int removeElements( OMSMetaData metaData, DataSource dataSource, OMSElement[] elements, int userId )
	throws Exception
	{
		if( !( elements.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.removeElements( metaData, dataSource, elements, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ elements.length ][];
		for( int i = 0; i < elements.length; i++ )
		{
			vars[ i ] = new BoundVariable[]{ new BoundVariable( "in_int_id", new Integer( elements[ i ].getId() ) ) };
		}
		return executeBatch( dataSource, BATCH_RESOURCE_REMOVE_ELEMENTS, vars );
	}
	
	int removeSimpleValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.removeSimpleValues( metaData, dataSource, values, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for( int i = 0; i < values.length; i++ )
		{
			vars[ i ] = new BoundVariable[]{ new BoundVariable( "in_int_id", new Integer( values[ i ].getId() ) ) };
		}
		return executeBatch( dataSource, BATCH_RESOURCE_REMOVE_SIMPLE_VALUES, vars );
	}

	int removeBlobValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.removeBlobValues( metaData, dataSource, values, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for( int i = 0; i < values.length; i++ )
		{
			vars[ i ] = new BoundVariable[]{ new BoundVariable( "in_int_id", new Integer( values[ i ].getId() ) ) };
		}
		return executeBatch( dataSource, BATCH_RESOURCE_REMOVE_BLOB_VALUES, vars );
	}

	int removeClobValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.removeClobValues( metaData, dataSource, values, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for( int i = 0; i < values.length; i++ )
		{
			vars[ i ] = new BoundVariable[]{ new BoundVariable( "in_int_id", new Integer( values[ i ].getId() ) ) };
		}
		return executeBatch( dataSource, BATCH_RESOURCE_REMOVE_CLOB_VALUES, vars );
	}

	int removeUniqueValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.removeUniqueValues( metaData, dataSource, values, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for( int i = 0; i < values.length; i++ )
		{
			vars[ i ] = new BoundVariable[]{ new BoundVariable( "in_int_id", new Integer( values[ i ].getId() ) ) };
		}
		return executeBatch( dataSource, BATCH_RESOURCE_REMOVE_UNIQUE_VALUES, vars );
	}

	int removeAssociations( OMSMetaData metaData, DataSource dataSource, Relation[] associations, int userId )
	throws Exception
	{
		if( !( associations.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.removeAssociations( metaData, dataSource, associations, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ associations.length ][];
		for( int i = 0; i < associations.length; i++ )
		{
			vars[ i ] = new BoundVariable[]{ new BoundVariable( "in_int_id", new Integer( associations[ i ].getId() ) ) };
		}
		return executeBatch( dataSource, BATCH_RESOURCE_REMOVE_ASSOCIATIONS, vars );
	}

	int removeCompositions( OMSMetaData metaData, DataSource dataSource, Relation[] compositions, int userId )
	throws Exception
	{
		if( !( compositions.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.removeCompositions( metaData, dataSource, compositions, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ compositions.length ][];
		for( int i = 0; i < compositions.length; i++ )
		{
			vars[ i ] = new BoundVariable[]{ new BoundVariable( "in_int_id", new Integer( compositions[ i ].getId() ) ) };
		}
		return executeBatch( dataSource, BATCH_RESOURCE_REMOVE_COMPOSITIONS, vars );
	}
	
	int updateElements( OMSMetaData metaData, DataSource dataSource, OMSElement[] elements, int userId )
	throws Exception
	{
		if( !( elements.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.updateElements( metaData, dataSource, elements, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ elements.length ][];
		for (int i = 0; i < elements.length; i++)
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( elements[ i ].getId() ) ),
				new BoundVariable( "in_string_display_name", elements[ i ].getDisplayName() ),
				new BoundVariable( "in_string_bookmark", elements[ i ].getBookmark() ),
				new BoundVariable( "in_int_modifier_id", new Integer( userId ) ),
			};
		}
		int result =executeBatch( dataSource, BATCH_RESOURCE_UPDATE_ELEMENTS, vars );
		resetState( elements );
		return result;
	}

	int updateSimpleValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.updateSimpleValues( metaData, dataSource, values, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for (int i = 0; i < values.length; i++)
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( values[ i ].getId() ) ),
				new BoundVariable( "in_string_content", values[ i ].getContentAsString() ),
				new BoundVariable( "in_int_modifier_id", new Integer( userId ) ),
			};
		}
		int result = executeBatch( dataSource, BATCH_RESOURCE_UPDATE_SIMPLE_VALUES, vars );
		resetState( values );
		return result;
	}

	int updateClobValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.updateClobValues( metaData, dataSource, values, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for (int i = 0; i < values.length; i++)
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( values[ i ].getId() ) ),
				new BoundVariable( "in_clob_content", values[ i ].getContentAsString() ),
				new BoundVariable( "in_int_modifier_id", new Integer( userId ) ),
			};
		}
		int result = executeBatch( dataSource, BATCH_RESOURCE_UPDATE_CLOB_VALUES, vars );
		resetState( values );
		return result;
	}

	int updateBlobValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.updateBlobValues( metaData, dataSource, values, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for (int i = 0; i < values.length; i++)
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( values[ i ].getId() ) ),
				new BoundVariable( "in_blob_content", values[ i ].getContentAsByteArray() ),
				new BoundVariable( "in_int_modifier_id", new Integer( userId ) ),
			};
		}
		int result = executeBatch( dataSource, BATCH_RESOURCE_UPDATE_BLOB_VALUES, vars );
		resetState( values );
		return result;
	}

	int updateUniqueValues( OMSMetaData metaData, DataSource dataSource, Value[] values, int userId )
	throws Exception
	{
		if( !( values.length >= dataSource.getMinimumBatchSize() ) )
		{
			return super.updateUniqueValues( metaData, dataSource, values, userId );
		}
		BoundVariable[][] vars = new BoundVariable[ values.length ][];
		for (int i = 0; i < values.length; i++)
		{
			vars[ i ] = new BoundVariable[]
			{
				new BoundVariable( "in_int_id", new Integer( values[ i ].getId() ) ),
				new BoundVariable( "in_string_content", values[ i ].getContentAsString() ),
				new BoundVariable( "in_int_modifier_id", new Integer( userId ) ),
			};
		}
		int result = executeBatch( dataSource, BATCH_RESOURCE_UPDATE_UNIQUE_VALUES, vars );
		resetState( values );
		return result;
	}

	int[] getSequenceValues( DataSource dataSource, String sequenceName, int length )
	throws Exception
	{
		int[] result = new int[ length ];
		BoundVariable[] vars = new BoundVariable[]
		{
			new BoundVariable( "out_cursor_values", null ),
			new BoundVariable( "in_int_count", length ),
		};
		HashMap<String, String> placeholders = new HashMap<String, String>();
		placeholders.put( "sequence_name", sequenceName );
		
		Record[] records = executeOnResource( dataSource, placeholders, vars, RESOURCE_GET_SEQUENCE_VALUES_FROM_ELEMENTS ).getRecordSets()[0].getRecords();
		int i = 0;
		for ( ; records != null && i < records.length; i++)
		{
			result[ i ] = bigDecimalAsInt( records[ i ].getValues()[ 0 ] );
		}
		while( i < ( length - 1 ) )
		{
			BoundVariable[] varsForDual = new BoundVariable[]
     		{
     			new BoundVariable( "out_cursor_values", null ),
     			new BoundVariable( "in_int_count", length - ( i + 1 ) ),
     		};
			records = executeOnResource( dataSource, placeholders, varsForDual, RESOURCE_GET_SEQUENCE_VALUES_FROM_DUAL ).getRecordSets()[0].getRecords();
			for ( int j = 0; records != null && j < records.length; j++)
			{
				result[ i++ ] = bigDecimalAsInt( records[ j ].getValues()[ 0 ] );
			}
		}
		
		return result;
	}
	
}
